import 'dart:async';
import 'dart:typed_data';

import 'package:app_updater/app_updater.dart';
import 'package:app_updater/entity/download_record.dart';
import 'package:app_updater/entity/download_status.dart';
import 'package:app_updater/entity/installation_record.dart';
import 'package:convert/convert.dart';
import 'package:get/get.dart';

import '../util/async_timer.dart';

const String _localPath = '/download/app.apk';

class AppUpdaterController extends GetxController {
  final AppUpdater _plugin = AppUpdater();

  final RxBool isInitialized = RxBool(false);
  // 下载记录
  final Rxn<DownloadRecord> downloadRecord = Rxn<DownloadRecord>();
  // 下载进度
  final Rxn<DownloadStatus> downloadStatus = Rxn<DownloadStatus>();
  // 安装记录
  final Rxn<InstallationRecord> installRecord = Rxn<InstallationRecord>();

  late final StreamSubscription<DownloadRecord?> _downloadRecordSubscription;
  AsyncTimer? _getDownloadStatusTimer;

  @override
  void onInit() {
    super.onInit();

    _downloadRecordSubscription =
        downloadRecord.listen(_onDownloadRecordUpdated);

    Future.wait(<Future<void>>[
      getDownloadRecord(),
      getInstallRecord(),
    ]).whenComplete(() {
      isInitialized.value = true;
      update();
    });
  }

  @override
  void onClose() {
    _downloadRecordSubscription.cancel();
    _getDownloadStatusTimer?.cancel();

    super.onClose();
  }

  Future<DownloadRecord?> getDownloadRecord() {
    return _plugin.downloadRecord.then((DownloadRecord? value) {
      downloadRecord.value = value;
      update();
      return value;
    });
  }

  Future<DownloadStatus?> getDownloadStatus(int id) {
    return _plugin.getDownloadStatus(id).then((DownloadStatus? value) {
      downloadStatus.value = value;
      update();
      return value;
    });
  }

  Future<InstallationRecord?> getInstallRecord() {
    return _plugin.installationRecord.then((InstallationRecord? value) {
      installRecord.value = value;
      update();
      return value;
    });
  }

  Future<DownloadRecord> commitDownload({
    required String version,
    required String url,
  }) {
    return _plugin
        .enqueueDownload(url: url, localPath: _localPath)
        .then((int downloadId) {
      return _plugin.reportDownload(version: version, downloadId: downloadId);
    }).then((DownloadRecord record) {
      downloadRecord.value = record;
      update();
      return record;
    });
  }

  Future<void> removeDownload(int id) {
    return _plugin.removeDownload(<int>[id]);
  }

  Future<String> calculateMD5Checksum(int id) {
    return _plugin.calculateMD5Checksum(id).then((Uint8List byteArr) {
      return hex.encode(byteArr);
    });
  }

  Future<bool> commitInstallation({
    required int downloadId,
    required String fromVersion,
    required String toVersion,
  }) {
    return _plugin.getUriForDownloadedFile(downloadId).then((Uri? uri) {
      if (uri == null) {
        return Future<bool>.value(false);
      }
      return _plugin
          .requestInstallAPK(uri.toString())
          .then((void value) => true);
    }).whenComplete(() {
      _plugin
          .reportInstallation(fromVersion: fromVersion, toVersion: toVersion)
          .then((InstallationRecord value) {
        installRecord.value = value;
        update();
        return value;
      });
    });
  }

  void _onDownloadRecordUpdated(DownloadRecord? record) {
    _getDownloadStatusTimer?.cancel();

    if (record == null) {
      return;
    }

    _getDownloadStatusTimer =
        AsyncTimer(const Duration(seconds: 1), (AsyncTimer timer) {
      return getDownloadStatus(record.downloadId);
    });
  }
}
